﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;

namespace Light.Aop.Interceptor
{
    /// <summary>
    /// 缓存拦截器
    /// </summary>
    public class CacheInterceptor : IMessageSink
    {
        private IMessageSink nextSink;
        public IMessageSink NextSink
        {
            get { return nextSink; }
        }
        public CacheInterceptor(IMessageSink nextSink)
        {
            this.nextSink = nextSink;
        }

        /// <summary>
        /// 同步处理方法
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public IMessage SyncProcessMessage(IMessage msg)
        {
            IMessage returnMsg = null;
            IMethodCallMessage call = msg as IMethodCallMessage;
            if (call == null || (Attribute.GetCustomAttribute(call.MethodBase, typeof(CacheMethodAttribute))) == null)
            {
                returnMsg = nextSink.SyncProcessMessage(msg);
            }
            else
            {
                CacheMethodAttribute attr = (CacheMethodAttribute)Attribute.GetCustomAttribute(call.MethodBase, typeof(CacheMethodAttribute));
                try
                {
                    using (ServiceStack.Redis.IRedisClient redis = Light.Cache.RedisHelper.GetClient())
                    {
                        bool isUpdate = attr.UpdateCache;
                        string keyPrefix = Helper.GetKeyPrefix(call.MethodBase, attr);

                        if (isUpdate && !String.IsNullOrEmpty(keyPrefix)) //删除指定前缀开头的缓存，下次查询时，重新获取最新数据
                        {
                            var keys = redis.GetAllKeys();
                            foreach (var key in keys)
                            {
                                if (key.StartsWith(keyPrefix))
                                {
                                    redis.Remove(key);
                                }
                            }
                            returnMsg = nextSink.SyncProcessMessage(msg);
                        }
                        else //尝试读取缓存，读不到，则从数据库获取并添加缓存
                        {
                            double expiresSeconds = attr.ExpiresSeconds;
                            string key = keyPrefix + "_" + Helper.GetCacheKey(call.MethodBase, call.Args);

                            var ser = new ServiceStack.Redis.Support.ObjectSerializer();
                            var value = redis.Get<byte[]>(key);
                            if (value == null || value.Length == 0)
                            {
                                returnMsg = nextSink.SyncProcessMessage(msg);
                                redis.Set(key, ser.Serialize(returnMsg), TimeSpan.FromSeconds(expiresSeconds));
                            }
                            else
                            {
                                returnMsg = (IMessage)ser.Deserialize(value);
                            }
                        }
                    }
                }
                catch
                {
                    returnMsg = nextSink.SyncProcessMessage(msg);
                }

            }

            return returnMsg;
        }

        /// <summary>
        /// 异步处理方法（暂不需要）
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="replySink"></param>
        /// <returns></returns>
        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            return null;
        }
    }
}
